package zyz.framework.dao.interceptor;

import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap.Builder;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.springframework.stereotype.Component;
import zyz.framework.util.ReflectUtil;

import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.Properties;

@Component
@Intercepts({@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class})})
public class ResultMapInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        if (!(invocation.getTarget() instanceof RoutingStatementHandler)) return invocation.proceed();

        RoutingStatementHandler statementHandler = (RoutingStatementHandler) invocation.getTarget();
        StatementHandler delegate = (StatementHandler) ReflectUtil.getFieldValue(statementHandler, "delegate");

        Object paramObj = delegate.getParameterHandler().getParameterObject();
        if (paramObj == null || !(paramObj instanceof Map)) return invocation.proceed();
        Map<String, Object> paramMap = (Map<String, Object>) paramObj;
        if (!paramMap.containsKey("getClazz")) return invocation.proceed();

        Class<?> resultEntity = null;
        try {
            resultEntity = (Class<?>) paramMap.get("getClazz");
        } catch (Exception e) {
        }

        MappedStatement mappedStatement = (MappedStatement) ReflectUtil.getFieldValue(delegate, "mappedStatement");
        mappedStatement.getConfiguration().setMapUnderscoreToCamelCase(true);

        Builder builder = new Builder(mappedStatement.getConfiguration(), mappedStatement.getResultMaps().get(0).getId(), resultEntity, new ArrayList<ResultMapping>());
        ReflectUtil.setFieldValue(mappedStatement, "resultMaps", Collections.singletonList(builder.build()));

        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }
}